package org.elucid.gadmin.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import javax.swing.text.PlainView;
import javax.swing.text.Segment;
import javax.swing.text.Utilities;

public class SQLView extends PlainView {


	private static HashMap<Pattern, Color> patternColors;
	private static final String KEYWORD_SELECT = "(SELECT)";
	private static final String KEYWORD_ILIKE = "(ILIKE)";
	private static final String KEYWORD_LIKE = "(LIKE)";
	private static final String KEYWORD_WHERE = "(WHERE)";
	private static final String KEYWORD_FROM = "(FROM)";
	private static final String KEYWORD_GROUPBY = "(GROUP\\s+BY)";
	private static final String KEYWORD_ORDERBY = "(ORDER\\s+BY)";
	private static final String KEYWORD_CASE = "(CASE)";
	private static final String KEYWORD_WHEN = "(WHEN)";
	private static final String KEYWORD_ELSE = "(ELSE)";
	private static final String KEYWORD_END = "(END)";
	private static final String KEYWORD_AS = "(AS\\s+)";
	private static final String KEYWORD_AND = "(AND)";
	
	private static final Color clBlue = new Color(0,0,205 );
	private static final Color clGreen = new Color(60,179,113 );
	private static final Color clRed = new Color(250,128,114);
	
	static {
		// NOTE: the order is important!
		patternColors = new LinkedHashMap<Pattern, Color>();
		patternColors.put(Pattern.compile(KEYWORD_SELECT, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_FROM, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_WHERE, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_LIKE, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_ILIKE, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_GROUPBY, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_ORDERBY, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_WHEN, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_ELSE, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_END, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_AS, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_CASE, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile(KEYWORD_AND, java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile("(current_date)", java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile("(interval)", java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile("(left)", java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile("(right)", java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile("(join)", java.util.regex.Pattern.CASE_INSENSITIVE), clBlue);
		patternColors.put(Pattern.compile("([0-9]+)", java.util.regex.Pattern.CASE_INSENSITIVE), clGreen );
//		patternColors.put(Pattern.compile("('.*?')", java.util.regex.Pattern.CASE_INSENSITIVE), clRed ); find text in single quotes - doesnt work
	}

	public SQLView(Element element) {

		super(element);

		// Set tabsize to 4 (instead of the default 8)
		getDocument().putProperty(PlainDocument.tabSizeAttribute, 4);
	}

	@Override
	protected int drawUnselectedText(Graphics graphics, int x, int y, int p0, int p1) throws BadLocationException {

		Document doc = getDocument();
		String text = doc.getText(p0, p1 - p0);

		Segment segment = getLineBuffer();

		SortedMap<Integer, Integer> startMap = new TreeMap<Integer, Integer>();
		SortedMap<Integer, Color> colorMap = new TreeMap<Integer, Color>();

		// Match all regexes on this snippet, store positions
		for (Map.Entry<Pattern, Color> entry : patternColors.entrySet()) {

			Matcher matcher = entry.getKey().matcher(text);

			while (matcher.find()) {
				startMap.put(matcher.start(1), matcher.end());
				colorMap.put(matcher.start(1), entry.getValue());
			}
		}

		// TODO: check the map for overlapping parts

		int i = 0;

		// Colour the parts
		for (Map.Entry<Integer, Integer> entry : startMap.entrySet()) {
			int start = entry.getKey();
			int end = entry.getValue();

			if (i < start) {
				graphics.setColor(Color.black);
				doc.getText(p0 + i, start - i, segment);
				x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
			}

			graphics.setColor(colorMap.get(start));
			i = end;
			doc.getText(p0 + start, i - start, segment);
			x = Utilities.drawTabbedText(segment, x, y, graphics, this, start);
		}

		// Paint possible remaining text black
		if (i < text.length()) {
			graphics.setColor(Color.black);
			doc.getText(p0 + i, text.length() - i, segment);
			x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
		}

		return x;
	}

}